/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl.section;

import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.json.utils.JsonUtils;
import com.comac.ins.isfd.constant.enums.IsfdAlgorithmConfigIsDefaultEnum;
import com.comac.ins.isfd.domain.vo.IsfdAlgorithmConfigVo;
import com.comac.ins.isfd.domain.vo.IsfdLayupEquivalentMaterialVo;
import com.comac.ins.isfd.service.IIsfdLayupEquivalentMaterialService;
import com.comac.ins.isfd.util.IsfdAlgorithmConfigPythonExecute;
import com.comac.ins.isfd.util.MapUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IsfdSectionWithAlgorithmConfigImpl {

    private static final String CALCULATE_CAP_PROFILE = "calculate_cap_profile";
    private static final String COMPUTE_CAP_SECTION_PROPERTIES = "compute_cap_section_properties";
    private static final String CALCULATE_I_PROFILE = "calculate_i_profile";
    private static final String COMPUTE_I_BEAM_PROPERTIES = "compute_i_beam_properties";
    private static final String CALCULATE_T_PROFILE = "calculate_t_profile";
    private static final String COMPUTE_T_SECTION_PROPERTIES = "compute_t_section_properties";
    private static final String CALCULATE_L_PROFILE = "calculate_l_profile";
    private static final String COMPUTE_L_SECTION_PROPERTIES = "compute_l_section_properties";
    private static final String CALCULATE_FC_PROFILE = "calculate_fc_profile";
    private static final String COMPUTE_C_CHANNEL_PROPERTIES = "compute_c_channel_properties";
    private static final String CALCULATE_FG_PROFILE = "calculate_fg_profile";
    private static final String COMPUTE_FLAT_BAR_PROPERTIES = "compute_flat_bar_properties";
    private static final String CALCULATE_FZ_PROFILE = "calculate_fz_profile";
    private static final String COMPUTE_Z_SECTION_PROPERTIES = "compute_z_section_properties";

    @Autowired
    private IIsfdLayupEquivalentMaterialService iIsfdLayupEquivalentMaterialService;

    @Autowired
    private IsfdAlgorithmConfigPythonExecute isfdAlgorithmConfigPythonExecute;

    /**
     * 型材库相关的计算
     * calculate_cap_profile
     * calculate_l_profile
     * calculate_fc_profile
     * calculate_fg_profile
     * calculate_fz_profile
     * calculate_i_profile
     * calculate_t_profile
     * 进行处理
     */
    public void calculate(List<Map<String, Object>> dataList, IsfdAlgorithmConfigVo isfdAlgorithmConfigVo) {
        Long algorithmConfigId = isfdAlgorithmConfigVo.getId();
        String algorithmName = isfdAlgorithmConfigVo.getAlgorithmName();
        String implementation = isfdAlgorithmConfigVo.getImplementation();
        String param = isfdAlgorithmConfigVo.getParam();
        Integer isDefault = isfdAlgorithmConfigVo.getIsDefault();
        for (Map<String, Object> data : dataList) {
            if (IsfdAlgorithmConfigIsDefaultEnum.DEFAULT_CONFIG.getValue().equals(isDefault)) {
                // 公共参数构造
                Map<String, Object> jsonParams = buildCommonParameters(data, algorithmName);
                if (jsonParams == null) continue;

                // 算法特定参数构造
                buildAlgorithmSpecificParameters(algorithmName, data, jsonParams);

                // 执行算法并合并结果
                executeAndMergeResult(algorithmConfigId, algorithmName, implementation, jsonParams, data);
            } else {
                Map<String, Object> jsonParams = JsonUtils.parseObject(param, Map.class);
                executeAndMergeResult(algorithmConfigId, algorithmName, implementation, jsonParams, data);
            }
        }
    }

    private Map<String, Object> buildCommonParameters(Map<String, Object> data, String algorithmName) {
        Map<String, Object> params = new HashMap<>();

        // 通用层参数构造（根据算法类型动态获取层数）
        List<IsfdLayupEquivalentMaterialVo> materials = getMaterialLayers(algorithmName, data);
        if (materials == null) return null;

        params.put("layer_parameters", materials.stream()
            .map(m -> Arrays.asList(
                m.getT(),
                m.getExx(),
                m.getGxy(),
                m.getRho(),
                m.getX()
            ))
            .collect(Collectors.toList()));

        return params;
    }

    private void buildAlgorithmSpecificParameters(String algorithmName,
                                                  Map<String, Object> data,
                                                  Map<String, Object> jsonParams) {
        switch (algorithmName) {
            case CALCULATE_CAP_PROFILE:
            case COMPUTE_CAP_SECTION_PROPERTIES:
                jsonParams.put("shape_parameters", Arrays.asList(
                    MapUtils.getDoubleValue(data, "alpha"),
                    MapUtils.getDoubleValue(data, "D"),
                    MapUtils.getDoubleValue(data, "H"),
                    MapUtils.getDoubleValue(data, "L"),
                    MapUtils.getDoubleValue(data, "R1"),
                    MapUtils.getDoubleValue(data, "R2")
                ));
                break;
            case CALCULATE_I_PROFILE:
            case COMPUTE_I_BEAM_PROPERTIES:
                jsonParams.put("shape_parameters", Arrays.asList(
                    MapUtils.getDoubleValue(data, "W1"),
                    MapUtils.getDoubleValue(data, "H"),
                    MapUtils.getDoubleValue(data, "W2")
                ));
                break;
            case CALCULATE_T_PROFILE:
            case COMPUTE_T_SECTION_PROPERTIES:
                jsonParams.put("shape_parameters", Arrays.asList(
                    MapUtils.getDoubleValue(data, "W"),
                    MapUtils.getDoubleValue(data, "H")
                ));
                break;
            case CALCULATE_L_PROFILE:
            case COMPUTE_L_SECTION_PROPERTIES:
                jsonParams.put("shape_parameters", Arrays.asList(
                    MapUtils.getDoubleValue(data, "H"),
                    MapUtils.getDoubleValue(data, "effectiveHeight")
                ));
                break;
            case CALCULATE_FC_PROFILE:
            case COMPUTE_C_CHANNEL_PROPERTIES:
                jsonParams.put("shape_parameters", Arrays.asList(
                    MapUtils.getDoubleValue(data, "W1"),
                    MapUtils.getDoubleValue(data, "H"),
                    MapUtils.getDoubleValue(data, "W2"),
                    MapUtils.getDoubleValue(data, "botOuterDistance")
                ));
                break;
            case CALCULATE_FG_PROFILE:
            case COMPUTE_FLAT_BAR_PROPERTIES:
                jsonParams.put("shape_parameters", Collections.singletonList(
                    MapUtils.getDoubleValue(data, "W")
                ));
                break;
            case CALCULATE_FZ_PROFILE:
            case COMPUTE_Z_SECTION_PROPERTIES:
                jsonParams.put("shape_parameters", Arrays.asList(
                    MapUtils.getDoubleValue(data, "W1"),
                    MapUtils.getDoubleValue(data, "H"),
                    MapUtils.getDoubleValue(data, "W2"),
                    MapUtils.getDoubleValue(data, "R")
                ));
                break;
        }
    }


    /**
     * 获取材料，根据默认算法来区分
     */
    private List<IsfdLayupEquivalentMaterialVo> getMaterialLayers(String algorithmName, Map<String, Object> data) {
        List<String> layerCodeKeys = getLayerCodeKeys(algorithmName);
        if (layerCodeKeys == null || layerCodeKeys.isEmpty()) {
            log.error("No layer code keys defined for algorithm: {}", algorithmName);
            return null;
        }

        List<IsfdLayupEquivalentMaterialVo> materials = new ArrayList<>();
        for (String key : layerCodeKeys) {
            String layerCode = MapUtils.getStringValue(data, key);
            if (layerCode == null) {
                log.error("Missing layer code key '{}' for algorithm {}", key, algorithmName);
                return null;
            }
            IsfdLayupEquivalentMaterialVo material = iIsfdLayupEquivalentMaterialService.queryByLayCode(layerCode);
            if (material == null) {
                log.error("Material not found for layer code '{}' (key: {}) in algorithm {}", layerCode, key, algorithmName);
                return null;
            }
            materials.add(material);
        }

        return materials;
    }

    private List<String> getLayerCodeKeys(String algorithmName) {
        switch (algorithmName) {
            case CALCULATE_CAP_PROFILE:
            case COMPUTE_CAP_SECTION_PROPERTIES:
                return Collections.singletonList("epLayerCode");
            case CALCULATE_I_PROFILE:
            case CALCULATE_FC_PROFILE:
            case COMPUTE_I_BEAM_PROPERTIES:
            case COMPUTE_C_CHANNEL_PROPERTIES:
                return Arrays.asList("t1LayerCode", "t2LayerCode", "t3LayerCode");
            case CALCULATE_T_PROFILE:
            case COMPUTE_T_SECTION_PROPERTIES:
                return Arrays.asList("t1LayerCode", "t2LayerCode");
            case CALCULATE_L_PROFILE:
            case CALCULATE_FG_PROFILE:
            case CALCULATE_FZ_PROFILE:
            case COMPUTE_L_SECTION_PROPERTIES:
            case COMPUTE_FLAT_BAR_PROPERTIES:
            case COMPUTE_Z_SECTION_PROPERTIES:
                return Collections.singletonList("tLayerCode");
            default:
                log.error("Unknown algorithm name: {}", algorithmName);
                return Collections.emptyList();
        }
    }

    private void executeAndMergeResult(Long algorithmConfigId, String algorithmName, String implementation,
                                       Map<String, Object> params, Map<String, Object> data) {
        String jsonData = JsonUtils.toJsonString(params);
        Map<String, Object> result = null;
        try {
            result = isfdAlgorithmConfigPythonExecute.excute(algorithmName, implementation, jsonData);
        } catch (Exception e) {
            log.error("执行失败: {}", e.getMessage(), e);
            throw new BaseException("执行失败: " + e.getMessage());
        }
        if (result != null) {
            data.put("algorithmConfigId",algorithmConfigId);
            data.putAll(result);
        }
    }
}
